package com.lee.boot.head.first.demo.aspect;


import com.lee.boot.head.first.demo.annotation.MessageLogAnnotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Map;
import java.util.TreeSet;

/**
 * @Auther: LiHeng
 * @Date: 2018/10/17 15:03
 * @Description: 切面类，对于向中旅发送报文的报文日志记录
 */
@Aspect
@Component
public class MessageLogAspect {

    final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    HttpServletRequest request;

    /**
     * 使用表达式定义切点
     * execution "（方法修饰符【可省略】 方法返回值类型 类的全路径.方法名【可用*】(方法参数)）"
     */
    @Pointcut(value = "execution( * com.lee.boot.head.first.demo.service.impl.UserEntityServiceImpl.add(..))")
    public void messageLog() {
    }

    /**
     * 使用注解定义切点
     */
    @Pointcut(value = "@annotation(com.lee.boot.head.first.demo.annotation.MessageLogAnnotation)")
    public void annotionMessageLog() {
    }

    /**
     * 方法执行前执行
     *
     * @param joinPoint
     */
    @Before(value = "annotionMessageLog()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("before ");
        //获得方法的入参数组
        Object[] args = joinPoint.getArgs();
        TreeSet<String> strings = new TreeSet<>();
        for (Object arg : args) {
            strings.add((String) arg);
        }
        strings.forEach(value -> System.out.println(value));


        System.out.println("name：" + request.getParameter("name"));


        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
        MessageLogAnnotation annotation = method.getAnnotation(MessageLogAnnotation.class);
        if (annotation == null) {
            logger.info("我没找到");
        }
        Signature signature1 = joinPoint.getSignature();
        Parameter[] parameters = method.getParameters();
        for (Parameter parameter : parameters) {
            // 这里打印的arg0
            System.out.println("name :" + parameter.getName());
            int modifiers = parameter.getModifiers();
            System.out.println();
        }

        DefaultParameterNameDiscoverer discoverer1 = new DefaultParameterNameDiscoverer();
        String[] parameterNames1 = discoverer1.getParameterNames(method);
        for (String parameterName : parameterNames1) {
            System.out.println(parameterName);
        }
    }

    /**
     * 环绕增强 在切点执行中执行
     *
     * @param point
     */
    @Around(value = "annotionMessageLog()")
    public Object doArround(ProceedingJoinPoint point) throws Throwable {
        Map<String, String[]> parameterMap = request.getParameterMap();


        System.out.println("arround before procced ");

        // 打印切点类型 这里的是method-execution
        System.out.println("kind :" + point.getKind());
        // 打印切点信息 简短 execution(AopTestServiceImpl.doSomeThing(..))
        System.out.println("shortString:" + point.toShortString());
        // 打印切点信息 详细 execution(public void com.lee.springboot.web.service.impl.AopTestServiceImpl.doSomeThing(java.lang.String))
        System.out.println("longString:" + point.toLongString());

//        System.out.println("name:" + request.getParameter("name"));

        //获得方法的入参值数组
        Object[] args = point.getArgs();
        System.out.println("入参数组长度：" + args.length);
        System.out.println("aaa" + Arrays.toString(args));
        // 方法的返回值
        Object proceed = point.proceed();


        System.out.println("arround after procced ");
        return proceed;
    }

    /**
     * 切点抛出异常时执行
     *
     * @param joinPoint
     * @param throwable 抛出的异常
     */
    @AfterThrowing(value = "annotionMessageLog()", throwing = "throwable")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable throwable) {
//        System.out.println("message:" + throwable.getMessage());

        System.out.println("afterThrow ");

    }

    /**
     * 类似于finally语句块，切点执行完一定执行 在afterReturning之前执行
     *
     * @param joinPoint
     */
    @After(value = "annotionMessageLog()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println(" do after ");

    }

    /**
     * 注解指定返回的参数名，切点的返回参数，这里是requestBank(String,String,int)的返回参数
     * 方法退出时执行
     *
     * @param ret
     */
    @AfterReturning(value = "annotionMessageLog()", returning = "ret")
    public void doAfterReturn(Object ret) {

        System.out.println("afterReturn ");
    }


}
